/**
 * @file buzzer.h
 * @author Pablo Jean Rozario (pablo.jean.eel@gmail.com)
 * @brief 本库用于蜂鸣器驱动，平台无关，可用于任意微控制器
 * @version 1.0
 * @date 2022-12-01
 *
 * @copyright Copyright (c) 2022
 *
 */

#ifndef APPLICATION_BUZZER_H_
#define APPLICATION_BUZZER_H_

#include <stdint.h>
#include <stddef.h>
#include <string.h>

#include "notes.h"
#include "ringtones.h"

/*
 * 枚举类型定义
 */

/**
 * @brief 蜂鸣器类型定义
 *
 * BUZZER_TYPE_PASSIVE：无源蜂鸣器，需要PWM驱动，可发出任意频率
 * BUZZER_TYPE_ACTIVE：有源蜂鸣器，仅需GPIO驱动，频率固定
 */
typedef enum
{
    BUZZER_TYPE_PASSIVE, // 无源蜂鸣器
    BUZZER_TYPE_ACTIVE   // 有源蜂鸣器
} buzzer_type_e;

/**
 * @brief 蜂鸣器启动时的播放模式
 *
 * BUZZER_LOOP_OFF：仅播放一次，持续指定时间
 * BUZZER_LOOP_ON：间歇性响铃，开关交替
 */
typedef enum
{
    BUZZER_LOOP_OFF, // 不循环
    BUZZER_LOOP_ON   // 循环
} buzzer_loop_e;

/**
 * @brief 蜂鸣器当前是否处于活动状态
 *
 * BUZZER_IS_NOT_ACTIVE：无任务在处理蜂鸣器
 * BUZZER_IS_ACTIVE：有任务在处理蜂鸣器
 */
typedef enum
{
    BUZZER_IS_NOT_ACTIVE, // 非活动
    BUZZER_IS_ACTIVE      // 活动
} buzzer_active_e;

/**
 * @brief 蜂鸣器错误码
 *
 * BUZZER_ERR_OK：正常
 * BUZZER_ERR_FAIL：初始化失败
 * BUZZER_ERR_PARAMS：参数错误
 * BUZZER_ERR_UNKNOWN：未知错误
 */
typedef enum
{
    BUZZER_ERR_OK,
    BUZZER_ERR_FAIL,
    BUZZER_ERR_PARAMS,

    BUZZER_ERR_UNKNOWN = 0xFF
} buzzer_err_e;

/**
 * @brief 蜂鸣器提示音类型枚举
 *
 * 定义了常用的蜂鸣器提示音类型,用于系统状态提示
 */
typedef enum
{
    BUZZER_TONE_NONE = 0,   // 无提示音
    BUZZER_TONE_WARNING,    // 警告提示音(200ms-200ms-200ms)
    BUZZER_TONE_ERROR,      // 错误提示音(500ms-500ms)
    BUZZER_TONE_SUCCESS,    // 成功提示音(100ms-300ms-100ms)
    BUZZER_TONE_ALARM_LOOP, // 报警提示音(200ms-200ms)
    BUZZER_TONE_MAX         // 提示音类型最大值
} buzzer_tone_e;

/*
 * 函数指针类型定义
 */

/**
 * @brief PWM输出函数指针
 * @param freq 频率，0表示关闭PWM
 */
typedef void (*pwmOutFx)(uint32_t freq);

/**
 * @brief GPIO输出函数指针
 * @param val 输出高低电平
 */
typedef void (*gpioOutFx)(uint32_t val);

/*
 * 结构体定义
 */

typedef struct
{
    // 用户必须定义的参数
    struct
    {
        /**
         * @brief PWM频率控制函数
         * 传入0需关闭PWM输出
         * 用于无源蜂鸣器
         */
        pwmOutFx pwmOut;
        /**
         * @brief GPIO控制函数
         * 用于有源蜂鸣器
         */
        gpioOutFx gpioOut;

        // 只需选择其中一个函数，另一个必须为NULL
    } fnx;

    // buzzer_interrupt() 的中断周期，单位ms
    // buzzer_start() 和 buzzer_start_array() 的必要参数
    uint_fast16_t interruptMs;

    // 库内部变量,无需用户操作
    uint8_t started;        // 启动标志
    buzzer_type_e type;     // 蜂鸣器类型
    buzzer_active_e active; // 工作状态
    uint_fast16_t counting; // 计数器
    struct
    {
        uint16_t *pTimes;  // 时间数组指针
        uint16_t *pFreq;   // 频率数组指针
        uint_fast16_t i;   // 当前索引
        uint_fast16_t len; // 数组长度

        int_fast32_t time;  // 当前时间
        uint_fast16_t freq; // 当前频率

        buzzer_loop_e loop; // 循环模式
    } play_param;           // 播放参数
} buzzer_t;

extern buzzer_t buzzer;

/*
 * 函数声明
 */

/**
 * @brief 初始化蜂鸣器
 * @param buzzer 蜂鸣器句柄指针
 * @return buzzer_err_e 错误码
 */
buzzer_err_e buzzer_init(buzzer_t *buzzer);

/**
 * @brief 立即关闭蜂鸣器
 * @param buzzer 蜂鸣器句柄指针
 */
void buzzer_stop(buzzer_t *buzzer);

/**
 * @brief 立即打开蜂鸣器
 * @param buzzer 蜂鸣器句柄指针
 * @param freq   频率（仅无源蜂鸣器有效）
 */
void buzzer_turn_on(buzzer_t *buzzer, uint16_t freq);

/**
 * @brief 按指定周期启动蜂鸣器
 * @param buzzer 蜂鸣器句柄指针
 * @param freq   频率（仅无源蜂鸣器有效）
 * @param period 持续时间或响铃周期
 * @param loop   是否循环
 */
void buzzer_start(buzzer_t *buzzer, uint16_t freq, uint16_t period, buzzer_loop_e loop);

/**
 * @brief 播放一组时长和频率数组（如铃声）
 * @param buzzer  蜂鸣器句柄指针
 * @param pPeriod 时长数组
 * @param pFreq   频率数组（与pPeriod等长）
 * @param len     数组长度
 */
void buzzer_start_array(buzzer_t *buzzer, uint16_t *pPeriod, uint16_t *pFreq, uint16_t len);

/**
 * @brief 查询蜂鸣器是否处于活动状态
 * @param buzzer 蜂鸣器句柄指针
 * @return buzzer_active_e 活动状态
 */
buzzer_active_e buzzer_is_active(buzzer_t *buzzer);

/**
 * @brief 定时调用此函数以驱动蜂鸣器（建议在RTOS任务或定时器中调用）
 * @param buzzer 蜂鸣器句柄指针
 */
void buzzer_interrupt(buzzer_t *buzzer);

/**
 * @brief 当数组播放完成时的回调
 * @param buzzer 蜂鸣器句柄指针
 */
void buzzer_end_callback(buzzer_t *buzzer);

#endif /* APPLICATION_BUZZER_H_ */
